package com.ku.kill.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.ku.kill.controller.vo.UserVO;
import com.ku.kill.dataobject.UserDO;
import com.ku.kill.dataobject.UserPasswordDO;
import com.ku.kill.error.BusinessException;
import com.ku.kill.error.EmBusinessError;
import com.ku.kill.response.CommonReturnType;
import com.ku.kill.service.UserService;
import com.ku.kill.service.model.UserModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;


/**
 * @program: kill2
 * @description: UserController
 * @author: JokerKu
 * @create: 2020-04-02 15:23
 **/
@RestController()
@RequestMapping("/user")
@Slf4j
@CrossOrigin(allowCredentials = "true", allowedHeaders = "*")//跨域请求
// allowedHeaders = "*":允许跨域传输所有header参数，将用于使用token放入header域做session共享的跨域请求
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private HttpServletRequest httpServletRequest;
    @Autowired
    private StringRedisTemplate redisTemplate;

    //用户登录
    @PostMapping("/login")
    public CommonReturnType login(@RequestParam("password") String password,
                                  @RequestParam("telphone") String telphone) throws BusinessException {

        if (StrUtil.isBlank(password) || StrUtil.isBlank(telphone)) {
            log.error("用户登录出现异常：{}", "手机号或密码不能为空");
            throw new BusinessException(EmBusinessError.PARMATER_VALIDATION_ERROR, "手机号或密码不能为空");
        }
        UserModel userModel = userService.validateLogin(SecureUtil.md5(password), telphone);
        UserVO userVO = convertFromModel(userModel);
        //用户信息验证成功
        //将登录凭证加入到用户登录成功的session内
//        httpServletRequest.getSession().setAttribute("IS_LOGIN",true);
//        httpServletRequest.getSession().setAttribute("LOGIN_USER",userVO);

        //现在不用session来存储用户信息了，使用Redis
        //若用户登录验证成功后，将对应的登录信息和登录凭证一起存入redis中
        //1.生成token
        String token = "USER:" + IdUtil.fastSimpleUUID();
        //建立token和用户间的联系
        redisTemplate.opsForValue().set(token, JSONUtil.toJsonStr(userVO), 1, TimeUnit.HOURS);//1个小时过期时间
        //下发token
        return CommonReturnType.create(token);
    }

    //用户注册接口
    @PostMapping(value = "/register")
    public CommonReturnType register(@RequestParam(name = "telphone") String telphone,
                                     @RequestParam(name = "otpCode") String otpCode,
                                     @RequestParam(name = "name") String name,
                                     @RequestParam(name = "gender") Integer gender,
                                     @RequestParam(name = "age") Integer age,
                                     @RequestParam(name = "password") String password) throws BusinessException {
        //验证手机号和对应的otpcode相符合
        String inSessionOtpCode = (String) this.httpServletRequest.getSession().getAttribute(telphone);
        if (!StrUtil.equals(otpCode, inSessionOtpCode)) {
            log.error("用户注册出现异常：{}", "短信验证码不符合");
            throw new BusinessException(EmBusinessError.PARMATER_VALIDATION_ERROR, "短信验证码不符合");
        }
        //用户的注册流程
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setGender(new Byte(String.valueOf(gender.intValue())));
        userModel.setAge(age);
        userModel.setTelphone(telphone);
        userModel.setRegisterMode("byphone");
        userModel.setEncrptPasswprd(SecureUtil.md5(password));
        userService.register(userModel);

        return CommonReturnType.create(null);
    }


    //用户获取otp短信接口
    @PostMapping(value = "/getOtp")
    public CommonReturnType getOtp(@RequestParam(name = "telphone") String telphone) throws BusinessException {

        //限制一个手机号一个小时只能发送5次验证码
        String count = redisTemplate.opsForValue().get(telphone);
        if (StrUtil.isNotBlank(count) && Integer.parseInt(count) >= 5) {
            throw new BusinessException(EmBusinessError.OTP_COUNT_FULL);
        }
        if (StrUtil.isBlank(count)) {
            redisTemplate.opsForValue().set(telphone,"0",24,TimeUnit.HOURS); //24小时过期
        } else {
            redisTemplate.opsForValue().increment(telphone);
        }


        //需要按照一定的规则生成OTP验证码
        Random random = new Random();
        int randomInt = random.nextInt(99999); //会随机生成一个整数，这个整数的范围就是int类型的范围-2^31 ~ 2^31-1,但是如果在nextInt()括号中加入一个整数a那么，这个随机生成的随机数范围就变成[0,a)。
//        randomInt += 10000;
        String otpCode = String.valueOf(randomInt);


        //将OTP验证码同对应用户的手机号关联，使用httpsession的方式绑定他的手机号与OTPCODE
        httpServletRequest.getSession().setAttribute(telphone, otpCode);

        //将OTP验证码通过短信通道发送给用户,省略
        log.warn("**** telphone = " + telphone + " & otpCode = " + otpCode);
        return CommonReturnType.create(null);
    }


    //查询用户
    @RequestMapping("/get")
    public CommonReturnType getUser(@RequestParam(name = "id") Integer id) throws BusinessException {
        //1.查询数据库
//        UserModel userModel = userService.getUserById(id);
        //走缓存
        UserModel userModel = userService.getUserByIdInCache(id);

        //若获取的用户信息不存在
        if (userModel == null) {
            throw new BusinessException(EmBusinessError.USER_NOT_EXIT);
        }
        //2.将核心领域模型（service层）对象转换为可供前端使用的viewObject
        UserVO userVO = convertFromModel(userModel);
        //3.以通用结果的方式返回给前端
        return CommonReturnType.create(userVO);
    }

    //将核心领域模型（service层）对象转换为可供前端使用的viewObject
    private UserVO convertFromModel(UserModel userModel) {
        if (userModel == null) {
            return null;
        }
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(userModel, userVO);
        return userVO;
    }


}
